package com.hancher.common.androidutil;

import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.text.TextUtils;
import android.util.Log;

import com.hancher.common.base.BaseApplication;
import com.hancher.common.javautil.DateUtil;
import com.hancher.common.javautil.EmptyUtil;
import com.hancher.common.javautil.GsonUtil;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Arrays;
import java.util.HashMap;

/**
 * 作者：Hancher
 * 时间：2019/1/12.
 * 邮箱：ytu_shaoweijie@163.com
 * 版本：v1.0
 * <point>
 * 说明：
 */
public class LogUtil {
    private static final String TAG = "HancherLogUtil";

    public final static boolean FORCE = true;

    public final static int VERBOSE = 0x1;
    public final static int INFO = 0x2;
    public final static int DEBUG = 0x4;
    public final static int WARNING = 0x8;
    public final static int ERROR = 0x16;
    public final static int SHOW = INFO | ERROR;

    public final static boolean SYSOUT = false;
    private final static boolean WRITE_TO_FILE = false;
    private static String logFile = null;
    private static boolean initLogFile = false;

    /**
     * 打印调用逻辑，多行显示
     *
     * @param message
     * @return
     */
    private static String formatAllMessage(String message) {
        StackTraceElement[] targetElement = Thread.currentThread().getStackTrace();
        StringBuffer str = new StringBuffer();
        for (int i = 0; i < targetElement.length; i++) {

            String fileName = targetElement[i].getFileName();   //文件名
            String className = targetElement[i].getClassName(); //类名
            int lineNum = targetElement[i].getLineNumber();     //行数
            String methName = targetElement[i].getMethodName(); //方法名

            if (EmptyUtil.isEmpty(fileName) || fileName.length() < 5) {
                continue;
            } else {
                str.append(fileName.substring(0, fileName.length() - 4));
            }
            str.append(methName)
                    .append("(): ")
                    .append(message)
                    .append(" (")
                    .append(fileName)
                    .append(":")
                    .append(lineNum)
                    .append(")");
            if (i != targetElement.length - 1) {
                str.append("\n");
            }

        }
        return str.toString();
    }

    /**
     * 格式化文本，格式化成如下模样<br>
     * LogTestActivity.onCreate(): Hello World (LogTestActivity.java:12)
     *
     * @param message
     * @return
     */
    private static String formatMessage(String message, int i) {
        /**
         * i=2 HancherLogUtil.formatMessage()
         * i=3 HancherLogUtil.print()
         * i=4 HancherLogUtil.v()
         * i=5 who call it
         */
        StackTraceElement[] targetElement = Thread.currentThread().getStackTrace();

        String fileName = targetElement[i].getFileName();   //文件名
        String className = targetElement[i].getClassName(); //类名
        int lineNum = targetElement[i].getLineNumber();     //行数
        String methName = targetElement[i].getMethodName(); //方法名

        //严格按(FileName:LineNuber)的格式来写 才可以定位，后面不能加东西的样子
//        String str =
//                fileName.substring(0, fileName.length() - 4) + methName + "(): " +
//                        message +
//                        " (" + fileName + ":" + lineNum + ")";
        String str2 = " (" + fileName + ":" + lineNum + ") "
                + methName + "(): "
                + message;
        return str2;
    }

    static void print(int type, Object... messages) {
        StringBuffer message = new StringBuffer();
        if (messages.length > 1 && (messages[0] instanceof String) && ((String) messages[0]).contains("%")) {
            Object[] messagesTmp = Arrays.copyOfRange(messages, 1, messages.length);
            message.append(String.format((String) messages[0], messagesTmp));
        } else {
            for (Object item : messages) {
                message.append(item);
            }
        }
        if (message.length() > 3000) {
            int i = 0;
            while (i * 3000 < message.length()) {
                String message3;
                if ((i + 1) * 3000 > message.length()) {
                    message3 = formatMessage(message.substring(i * 3000, message.length()), 5);

                } else {
                    message3 = formatMessage(message.substring(i * 3000, (i + 1) * 3000), 5);
                }

                switch (type) {
                    case INFO:
                        Log.i(TAG, message3);
                        break;
                    case DEBUG:
                        Log.d(TAG, message3);
                        break;
                    case WARNING:
                        Log.w(TAG, message3);
                        break;
                    case ERROR:
                        Log.e(TAG, message3);
                        break;
                    default:
                        Log.v(TAG, message3);
                        break;
                }
                if (SYSOUT) {
                    System.out.println(message3);
                }
                writeToFile(message3);
                i++;
            }
            return;
        }
        if (FORCE || (SHOW & type) != 0) {
            String formatMessage;
            if (message.toString().startsWith("全埋点")) {
                formatMessage = message.toString();
            } else {
                formatMessage = formatMessage(message.toString(), 5);
            }
            switch (type) {
                case INFO:
                    Log.i(TAG, formatMessage);
                    break;
                case DEBUG:
                    Log.d(TAG, formatMessage);
                    break;
                case WARNING:
                    Log.w(TAG, formatMessage);
                    break;
                case ERROR:
                    Log.e(TAG, formatMessage);
                    break;
                default:
                    Log.v(TAG, formatMessage);
                    break;
            }
            if (SYSOUT) {
                System.out.println(formatMessage);
            }
            writeToFile(formatMessage);
        }
    }

    public static void v(Object... message) {
        if (ApkInfoUtil.isApkInDebug(BaseApplication.getInstance())) {
            print(VERBOSE, message);
        }
    }

    public static void i() {
        print(INFO, "");
    }

    public static void i(Object... message) {
        print(INFO, message);
    }

    public static void d() {
        if (ApkInfoUtil.isApkInDebug(BaseApplication.getInstance())) {
            print(DEBUG, "");
        }
    }

    public static void d(Object... message) {
        if (ApkInfoUtil.isApkInDebug(BaseApplication.getInstance())) {
            print(DEBUG, message);
        }
    }

    public static void w(Object... message) {
        print(WARNING, message);
    }

    public static void e(Throwable e) {
        print(ERROR, e);
        for (int i = 0; i < e.getStackTrace().length; i++) {
            print(ERROR, e.getStackTrace()[i] + " ");
        }
    }

    public static void e(Object... message) {
        print(ERROR, message);
    }

    public static void e(String message, Throwable e) {
        StringBuffer err = new StringBuffer(message);
        err.append(" ").append(e.getMessage());
        StackTraceElement[] errTrace = e.getStackTrace();
        for (StackTraceElement item : errTrace) {
            err.append("\n").append(item.toString());
        }
        print(ERROR, err.toString());
    }

    public static void intent(Intent intent) {
        if (intent == null) {
            print(DEBUG, "intent null");
            return;
        }
        StringBuffer message = new StringBuffer("intent:");
        message.append("\nflag=").append(intent.getFlags());

        Bundle bundle = intent.getExtras();
        if (bundle != null) {
            message.append("\nbundle=[");
            int i = 0;
            for (String key : bundle.keySet()) {
                message.append(key).append(":").append(bundle.getString(key));
                i++;
                if (i != bundle.size()) {
                    message.append(",");
                }
            }
            message.append("]");
        }
        print(DEBUG, message.toString());
    }

    public static void point(String message) {
        if (FORCE || (SHOW & DEBUG) != 0) {
            String formatMessage = formatAllMessage(message);
            Log.d(TAG, formatMessage);
            writeToFile(formatMessage);
        }
    }

    public static String o(Object obj) {
        if (FORCE || (SHOW & DEBUG) != 0) {
            String formatMessage = GsonUtil.obj2JsonStr(obj);
            print(VERBOSE, formatMessage);
            writeToFile(formatMessage);
            return formatMessage;
        }
        return null;
    }

    public static void map2Json(Object... message) {
        HashMap<String, String> map = new HashMap<>();
        for (int i = 1; i < message.length; i += 2) {
            map.put(message[i].toString(), message[i + 1].toString());
        }
        String newMessage = message[0] + GsonUtil.obj2JsonStr(map);
        if (ApkInfoUtil.isApkInDebug(BaseApplication.getInstance())) {
            print(VERBOSE, newMessage);
        }
    }

    /**
     * 初始化文件
     *
     * @param context
     */
    public static void initWriteToFile(Context context) {
        if (!WRITE_TO_FILE) {
            return;
        }
        if (TextUtils.isEmpty(logFile)) {
            if (context == null) {
                e("还没初始化就使用文件输出无法继续进行");
                return;
            }
            String parentDir = context.getExternalFilesDir("log").getAbsolutePath();
            File file = new File(parentDir);
            if (!file.exists()) {
                file.mkdirs();
            }
            logFile = parentDir + File.separator + "hancher.log";
        }
        initLogFile = true;
        i("初始化成功，开始记录日志：");
    }

    /**
     * 需要先调用initWriteToFile
     *
     * @param message
     */
    private static void writeToFile(String message) {
        if (!WRITE_TO_FILE || !initLogFile) {
            return;
        }

        FileWriter writer = null;
        try {
            writer = new FileWriter(logFile, true);
            writer.write(DateUtil.getAllstr() + " " + message + "\n");
            writer.flush();
            writer.close();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (writer != null) {
                try {
                    writer.close();
                } catch (IOException e) {
                    e.printStackTrace();
                    e("关闭输出失败e=" + e);
                }
            }
        }
    }
}
